﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text.RegularExpressions;

namespace 验证码识别
{
    public class ImageMap
    {
        /// <summary>
        /// 图片全局容器
        /// </summary>
        public Bitmap bm;

        /// <summary>
        /// 图片分割后的容器
        /// </summary>
        Bitmap[] bs;

        /// <summary>
        /// 验证码特征对象
        /// </summary>
        ABC code = new ABC();

        /// <summary>
        /// 验证码容器
        /// </summary>
        string s = "";

        public ImageMap() { }

        /// <summary>
        /// 设置图片灰度
        /// </summary>
        /// <returns>处理后的图片</returns>
        public Bitmap huidu()
        {
            for(int i = 0; i < bm.Height; i++)
            {                
                for (int j = 0; j < bm.Width; j++)
                {
                    int tmpValue = GetGrayNumColor(bm.GetPixel(j, i));
                    bm.SetPixel(j, i, Color.FromArgb(tmpValue, tmpValue, tmpValue));
                }
            }
            return bm;
        }

        /// <summary>
        /// 设置图片灰度
        /// </summary>
        /// <param name="b">要处理成灰度的图片</param>
        /// <returns>处理后的图片</returns>
        public Bitmap huidu(Bitmap b)
        {
            for (int i = 0; i < b.Height; i++)
            {
                for (int j = 0; j < b.Width; j++)
                {
                    int tmpValue = GetGrayNumColor(b.GetPixel(j, i));
                    b.SetPixel(j, i, Color.FromArgb(tmpValue, tmpValue, tmpValue));
                }
            }
            return b;
        }

        /// <summary>
        /// 根据RGB，计算灰度值
        /// </summary>
        /// <param name="color">Color值</param>
        /// <returns>灰度值,整形</returns>
        private int GetGrayNumColor(System.Drawing.Color posClr)
        {
            return (posClr.R * 19595 + posClr.G * 38469 + posClr.B * 7472) >> 16;
        }

        /// <summary>
        /// 阈值处理
        /// </summary>
        /// <param name="er">阈值</param>
        public Bitmap yuzhi(int er)
        {
            Color ColorOrigin = new Color();//定义一个色彩变量对象
            double Red, Green, Blue, Y; //定义红、绿、蓝三色和亮度
            for (int i = 0; i <= bm.Width - 1; i++)
            {
                for (int j = 0; j <= bm.Height - 1; j++)//循环处理图像中的每一个像素点
                {
                    ColorOrigin = bm.GetPixel(i, j); //获取当前像素点的色彩信息
                    Red = ColorOrigin.R; //获取当前像素点的红色分量
                    Green = ColorOrigin.G; //获取当前像素点的绿色分量
                    Blue = ColorOrigin.B; //获取当前像素点的蓝色分量
                    Y = 0.59 * Red + 0.3 * Green + 0.11 * Blue; //计算当前像素点的亮度
                    if (Y > er) //如果当前像素点的亮度大于指定阈值
                    {
                        Color ColorProcessed = Color.FromArgb(255, 255, 255); //那么定义一个纯白的色彩变量，即各分量均为255
                        bm.SetPixel(i, j, ColorProcessed); //将白色变量赋给当前像素点
                    }
                    if (Y <= er) //如果当前像素点的亮度小于指定阈值
                    {
                        Color ColorProcessed = Color.FromArgb(0, 0, 0); //那么定义一个纯黑的色彩变量，即各分量均为0
                        bm.SetPixel(i, j, ColorProcessed); //将黑色变量赋给当前像素点
                    }
                }
            }
            return bm;
        }

        /// <summary>
        /// 去掉边框
        /// </summary>
        /// <param name="w">边框的像素值</param>
        /// <returns>去掉边框后的图片</returns>
        public Bitmap qubian(int w)
        {
            for (int i = 0; i < bm.Height; i++)
            {
                for (int j = 0; j < bm.Width; j++)
                {
                    if (i < w || j < w || j > bm.Width - 1 - w || i > bm.Height - 1 - w)
                        bm.SetPixel(j, i, Color.FromArgb(255, 255, 255));
                }
            }
            bm.MakeTransparent(Color.White);
            return bm;
        }

        /// <summary>
        /// 去除噪点
        /// </summary>
        /// <returns>去掉噪点后的图片</returns>
        public Bitmap zaodian()
        {
            bm.MakeTransparent(Color.White);
            for (int i = 2; i < bm.Width - 2; i++)
            {
                for (int j = 2; j < bm.Height - 2; j++)
                {
                    if (Color.Black.A == bm.GetPixel(i, j).A)
                    {
                        //选择黑点
                        if (bm.GetPixel(i - 1, j - 1).A.ToString() == "0" && bm.GetPixel(i, j - 1).A.ToString() == "0" && bm.GetPixel(i + 1, j - 1).A.ToString() == "0" && bm.GetPixel(i - 1, j).A.ToString() == "0" && bm.GetPixel(i + 1, j).A.ToString() == "0" && bm.GetPixel(i - 1, j + 1).A.ToString() == "0" && bm.GetPixel(i, j + 1).A.ToString() == "0" && bm.GetPixel(i + 1, j + 1).A.ToString() == "0")
                        {
                            //如果一圈都是白的,就将他设置为白的
                            bm.SetPixel(i, j, Color.White);
                        }
                    }
                }
            }
            //bm.MakeTransparent(Color.White);
            return bm;
        }

        /// <summary>
        /// 图片分割
        /// </summary>
        /// <returns>返回分割后的图片集合</returns>
        public Bitmap[] fengeyouxiaotupian()
        {
            StringBuilder sb = new StringBuilder();
            List<canshu> lsz = new List<canshu>();
            for (int i = 0; i < bm.Width; i++)
            {
                string k = "";
                for (int j = 0; j < bm.Height; j++)
                {
                    k += bm.GetPixel(i, j).A.ToString();
                }
                //是否有黑点
                if (k.Contains("255"))
                {
                    //有黑点
                    sb.Append(1);
                }
                else
                {
                    //无黑点
                    sb.Append(0);
                }
            }
            //开始计算所要截取的坐标
            bool b = true;//是否记录初始值
            int one = 0;//初始横坐标
            int next = 0;//接受横坐标
            for (int i = 0; i < bm.Width; i++)
            {
                if (sb.ToString().Substring(i, 1) == "1")
                {
                    //遇见1
                    if (b)
                    {
                        //第一次可以见到
                        b = false;
                        one = i;//记录初始坐标
                    }
                    if (sb.ToString().Substring(i + 1, 1) == "0")
                    {
                        //已经是1的终点
                        next = i;
                        //开始截取
                        canshu sss = new canshu() { X = one, W = next - one, };
                        lsz.Add(sss);
                    }
                }
                else
                {
                    //遇见0
                    b = true;//初始化开始记录值
                }
            }
            bs = jiequ(bm, lsz.ToArray());
            return bs;
        }

        /// <summary>
        /// 返回分割图片
        /// </summary>
        /// <param name="b">要分割的图片</param>
        /// <param name="s">分割参数</param>
        /// <returns></returns>
        Bitmap[] jiequ(Bitmap b, canshu[] s)
        {
            Bitmap[] bs = new Bitmap[s.Count()];
            for (int q = 0; q < s.Count(); q++)
            {
                Bitmap bb = new Bitmap(s[q].W, b.Height);
                for (int i = s[q].X; i < s[q].X + s[q].W; i++)
                {
                    for (int j = 0; j < b.Height; j++)
                    {
                        bb.SetPixel(i - s[q].X, j, b.GetPixel(i, j));
                    }
                }
                bs[q] = bb;
            }
            return bs;
        }

        /// <summary>
        /// 获取单个验证码特征所对应的验证码
        /// </summary>
        /// <param name="k">验证码特征</param>
        /// <returns>验证码</returns>
        public string Code(string k)
        {
            code = null;
            if (!File.Exists("kxcxc.dat"))
            {
                return null;
            }
            using (FileStream fs = new FileStream("kxcxc.dat", FileMode.Open, FileAccess.Read))
            {
                BinaryFormatter format = new BinaryFormatter();
                code = (ABC)format.Deserialize(fs);
            }

            if (Regex.IsMatch(code.Wa, k, RegexOptions.IgnoreCase)) { return "a"; }
            if (Regex.IsMatch(code.Wb, k, RegexOptions.IgnoreCase)) { return "b"; }
            if (Regex.IsMatch(code.Wc, k, RegexOptions.IgnoreCase)) { return "c"; }
            if (Regex.IsMatch(code.Wd, k, RegexOptions.IgnoreCase)) { return "d"; }
            if (Regex.IsMatch(code.We, k, RegexOptions.IgnoreCase)) { return "e"; }
            if (Regex.IsMatch(code.Wf, k, RegexOptions.IgnoreCase)) { return "f"; }
            if (Regex.IsMatch(code.Wg, k, RegexOptions.IgnoreCase)) { return "g"; }
            if (Regex.IsMatch(code.Wh, k, RegexOptions.IgnoreCase)) { return "h"; }
            if (Regex.IsMatch(code.Wi, k, RegexOptions.IgnoreCase)) { return "i"; }
            if (Regex.IsMatch(code.Wj, k, RegexOptions.IgnoreCase)) { return "j"; }
            if (Regex.IsMatch(code.Wk, k, RegexOptions.IgnoreCase)) { return "k"; }
            if (Regex.IsMatch(code.Wl, k, RegexOptions.IgnoreCase)) { return "l"; }
            if (Regex.IsMatch(code.Wm, k, RegexOptions.IgnoreCase)) { return "m"; }
            if (Regex.IsMatch(code.Wn, k, RegexOptions.IgnoreCase)) { return "n"; }
            if (Regex.IsMatch(code.Wo, k, RegexOptions.IgnoreCase)) { return "o"; }
            if (Regex.IsMatch(code.Wp, k, RegexOptions.IgnoreCase)) { return "p"; }
            if (Regex.IsMatch(code.Wq, k, RegexOptions.IgnoreCase)) { return "q"; }
            if (Regex.IsMatch(code.Wr, k, RegexOptions.IgnoreCase)) { return "r"; }
            if (Regex.IsMatch(code.Ws, k, RegexOptions.IgnoreCase)) { return "s"; }
            if (Regex.IsMatch(code.Wt, k, RegexOptions.IgnoreCase)) { return "t"; }
            if (Regex.IsMatch(code.Wu, k, RegexOptions.IgnoreCase)) { return "u"; }
            if (Regex.IsMatch(code.Wv, k, RegexOptions.IgnoreCase)) { return "v"; }
            if (Regex.IsMatch(code.Ww, k, RegexOptions.IgnoreCase)) { return "w"; }
            if (Regex.IsMatch(code.Wx, k, RegexOptions.IgnoreCase)) { return "x"; }
            if (Regex.IsMatch(code.Wy, k, RegexOptions.IgnoreCase)) { return "y"; }
            if (Regex.IsMatch(code.Wz, k, RegexOptions.IgnoreCase)) { return "z"; }
            if (Regex.IsMatch(code.WA, k, RegexOptions.IgnoreCase)) { return "A"; }
            if (Regex.IsMatch(code.WB, k, RegexOptions.IgnoreCase)) { return "B"; }
            if (Regex.IsMatch(code.WC, k, RegexOptions.IgnoreCase)) { return "C"; }
            if (Regex.IsMatch(code.WD, k, RegexOptions.IgnoreCase)) { return "D"; }
            if (Regex.IsMatch(code.WE, k, RegexOptions.IgnoreCase)) { return "E"; }
            if (Regex.IsMatch(code.WF, k, RegexOptions.IgnoreCase)) { return "F"; }
            if (Regex.IsMatch(code.WG, k, RegexOptions.IgnoreCase)) { return "G"; }
            if (Regex.IsMatch(code.WH, k, RegexOptions.IgnoreCase)) { return "H"; }
            if (Regex.IsMatch(code.WI, k, RegexOptions.IgnoreCase)) { return "I"; }
            if (Regex.IsMatch(code.WJ, k, RegexOptions.IgnoreCase)) { return "J"; }
            if (Regex.IsMatch(code.WK, k, RegexOptions.IgnoreCase)) { return "K"; }
            if (Regex.IsMatch(code.WL, k, RegexOptions.IgnoreCase)) { return "L"; }
            if (Regex.IsMatch(code.WM, k, RegexOptions.IgnoreCase)) { return "M"; }
            if (Regex.IsMatch(code.WN, k, RegexOptions.IgnoreCase)) { return "N"; }
            if (Regex.IsMatch(code.WO, k, RegexOptions.IgnoreCase)) { return "O"; }
            if (Regex.IsMatch(code.WP, k, RegexOptions.IgnoreCase)) { return "P"; }
            if (Regex.IsMatch(code.WQ, k, RegexOptions.IgnoreCase)) { return "Q"; }
            if (Regex.IsMatch(code.WR, k, RegexOptions.IgnoreCase)) { return "R"; }
            if (Regex.IsMatch(code.WS, k, RegexOptions.IgnoreCase)) { return "S"; }
            if (Regex.IsMatch(code.WT, k, RegexOptions.IgnoreCase)) { return "T"; }
            if (Regex.IsMatch(code.WU, k, RegexOptions.IgnoreCase)) { return "U"; }
            if (Regex.IsMatch(code.WV, k, RegexOptions.IgnoreCase)) { return "V"; }
            if (Regex.IsMatch(code.WW, k, RegexOptions.IgnoreCase)) { return "W"; }
            if (Regex.IsMatch(code.WX, k, RegexOptions.IgnoreCase)) { return "X"; }
            if (Regex.IsMatch(code.WY, k, RegexOptions.IgnoreCase)) { return "Y"; }
            if (Regex.IsMatch(code.WZ, k, RegexOptions.IgnoreCase)) { return "Z"; }
            if (Regex.IsMatch(code.W0, k, RegexOptions.IgnoreCase)) { return "0"; }
            if (Regex.IsMatch(code.W1, k, RegexOptions.IgnoreCase)) { return "1"; }
            if (Regex.IsMatch(code.W2, k, RegexOptions.IgnoreCase)) { return "2"; }
            if (Regex.IsMatch(code.W3, k, RegexOptions.IgnoreCase)) { return "3"; }
            if (Regex.IsMatch(code.W4, k, RegexOptions.IgnoreCase)) { return "4"; }
            if (Regex.IsMatch(code.W5, k, RegexOptions.IgnoreCase)) { return "5"; }
            if (Regex.IsMatch(code.W6, k, RegexOptions.IgnoreCase)) { return "6"; }
            if (Regex.IsMatch(code.W7, k, RegexOptions.IgnoreCase)) { return "7"; }
            if (Regex.IsMatch(code.W8, k, RegexOptions.IgnoreCase)) { return "8"; }
            if (Regex.IsMatch(code.W9, k, RegexOptions.IgnoreCase)) { return "9"; }
            return null;
        }

        /// <summary>
        /// 获取验证码的特特
        /// </summary>
        /// <param name="danbm"></param>
        /// <returns></returns>
        public string yanzhengmtezheng(Bitmap danbm)
        {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < danbm.Width; i++)
            {
                for (int j = 0; j < danbm.Height; j++)
                {
                    sb.Append(danbm.GetPixel(i, j).A.ToString() == "255" ? 1 : 0);
                }
            }
            return ZIP(sb.ToString());
        }

        /// <summary>
        /// 压缩特征
        /// </summary>
        /// <param name="sb"></param>
        /// <returns></returns>
        private string ZIP(string sb)
        {
            StringBuilder s = new StringBuilder();
            string[] ss = sb.Replace("01", "0*1").Replace("10", "1*0").Split('*');
            for (int i = 0; i < ss.Count(); i++)
            {
                if (ss[i].Contains("1"))
                {
                    s.Append("1x" + ss[i].Count());
                }
                else
                {
                    s.Append("0x" + ss[i].Count());
                }
            }
            return s.ToString();
        }

        /// <summary>
        /// 获取验证码
        /// </summary>
        /// <returns></returns>
        public string huoquyanzhengma()
        {
            for (int i = 0; i < bs.Count(); i++)
            {
                string key = yanzhengmtezheng(bs[i]);
                s += Code(key);
            }
            return s;
        }
    }
}
